#ifndef CONCURRENT_QUEUE_H
#define CONCURRENT_QUEUE_H

#include <queue>

template<typename Data>
class concurrent_queue
{
private:
    std::queue<Data> the_queue;
	mutable HANDLE the_mutex;
public:
	concurrent_queue()
	{
		the_mutex = CreateMutex(NULL, false, NULL);
	}
	~concurrent_queue()
	{
		if (the_mutex != NULL)
		{
			CloseHandle(the_mutex);
		}
	}

    void push(Data const& data)
    {
		WaitForSingleObject(the_mutex, INFINITE);
        the_queue.push(data);
		ReleaseMutex(the_mutex);
    }

    bool empty() const
    {
		WaitForSingleObject(the_mutex, INFINITE);
		bool empty = the_queue.empty();
		ReleaseMutex(the_mutex);
        return empty;
    }

    bool try_pop(Data& popped_value)
    {
		WaitForSingleObject(the_mutex, INFINITE);
        if(the_queue.empty())
        {
			ReleaseMutex(the_mutex);
            return false;
        }
        
        popped_value = the_queue.front();
        the_queue.pop();
		ReleaseMutex(the_mutex);
        return true;
    }

	unsigned long size()
	{
		WaitForSingleObject(the_mutex, INFINITE);
		unsigned long retSize = the_queue.size();
		ReleaseMutex(the_mutex);
		return retSize;
	}

private :
	concurrent_queue(concurrent_queue& other);
	concurrent_queue & operator= (concurrent_queue & other);
};

#endif